package com.mmz.spring.aop.framework;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import org.aopalliance.aop.Advice;


import com.mmz.spring.aop.EmptyTargetSource;
import com.mmz.spring.aop.TargetSource;
import com.mmz.spring.aop.support.Advisor;

public class AdvisedSupport extends ProxyConfig implements Advised{
	
	public static final TargetSource EMPTY_TARGET_SOURCE = EmptyTargetSource.INSTANCE;

	TargetSource targetSource = EMPTY_TARGET_SOURCE;
	
	private transient Map<MethodCacheKey, List<Object>> methodCache;
	
	private List<Class<?>> interfaces = new ArrayList<Class<?>>();
	
	private List<Advisor> advisors = new LinkedList<Advisor>();
	
	private Advisor[] advisorArray = new Advisor[0];
	
	public void setAdvisorArray(Advisor[] advisorArray) {
		this.advisorArray = advisorArray;
	}

	// 通知器链工厂
	DefaultAdvisorChainFactory advisorChainFactory = new DefaultAdvisorChainFactory();
	
	public AdvisedSupport() {
		initMethodCache();
	}
	
	public AdvisedSupport(Class<?>[] interfaces) {
		this();
		setInterfaces(interfaces);
	}
	
	// 初始化目标对象接口
	public void setInterfaces(Class<?>... interfaces) {
		
		this.interfaces.clear();
		for (Class<?> ifc : interfaces) {
			if (!this.interfaces.contains(ifc)) {
				this.interfaces.add(ifc);
				this.methodCache.clear();
			}
		}
	}
	
	// 初始化通知器链Map
	private void initMethodCache() {
		this.methodCache = new ConcurrentHashMap<MethodCacheKey, List<Object>>(32);
	}
	
	public Class<?>[] getProxiedInterfaces() {
		return this.interfaces.toArray(new Class<?>[this.interfaces.size()]);
	}
	
	public Class<?> getTargetClass() {
		return this.targetSource.getTargetClass();
	}
	
	public final Advisor[] getAdvisors() {
		return this.advisorArray;
	}
	
	public TargetSource getTargetSource() {
		return this.targetSource;
	}
	
	public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method, Class<?> targetClass) {
		MethodCacheKey cacheKey = new MethodCacheKey(method);
		List<Object> cached = this.methodCache.get(cacheKey);
		if (cached == null) {
			cached = this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(
					this, method, targetClass);
			this.methodCache.put(cacheKey, cached);
		}
		return cached;
	}
	
	/**
	 * 静态内部类，作为通知器链的key，代表一个方法对应的拦截器链
	 * */
	private static class MethodCacheKey {

		private final Method method;

		private final int hashCode;

		public MethodCacheKey(Method method) {
			this.method = method;
			this.hashCode = method.hashCode();
		}

		@Override
		public boolean equals(Object other) {
			if (other == this) {
				return true;
			}
			MethodCacheKey otherKey = (MethodCacheKey) other;
			return (this.method == otherKey.method);
		}

		@Override
		public int hashCode() {
			return this.hashCode;
		}
		
		
	}

	public boolean isInterfaceProxied(Class<?> intf) {
		// TODO Auto-generated method stub
		return false;
	}

	public void setTargetSource(TargetSource targetSource) {
		this.targetSource = targetSource;
		
	}

	public void addAdvisor(Advisor advisor) {
		// TODO Auto-generated method stub
		
	}

	
}
